package cn.tedu.justone.pack01;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * ZZ：JustOne
 * VX：Andylau2020smile
 * DY：JustOne2018
 * ZT：《》
 */
public class Demo20_AtomicInteger原子计数器 {
    //
    //AtomicInteger原子计数器
    //AtomicInteger原子计数器
    //AtomicInteger原子计数器
    //1,由于i++不具有原子性，我们可以通过以下两种方式解决。
    //  a,为i++所在的方法加锁
    //  b,用Atomic包下的原子类
    //2,一个原子(atomic)类型就是一个原子操作可用的类型，它可以在没有锁的情况下做到线程安全。
    //3,添加volatile修饰 i 是无效的，仍然不具备元子性(关于volatile下一节讲)


    //本篇的重点是介绍AtomicInteger，请看MethodE();
    //AtomicInteger的常用方法：
    //AtomicInteger的常用方法：
    //AtomicInteger的常用方法：
    // AtomicInteger ai = new AtomicInteger(); 创建ai对象，值为0
    // AtomicInteger ai = new AtomicInteger(5);创建ai对象，值为5
    // ai.addAndGet()------- 以原子方式将给定值添加到当前值，并在添加后返回新值。
    // ai.getAndAdd()------- 以原子方式将给定值添加到当前值并返回旧值。
    // ai.incrementAndGet()- 以原子方式将当前值递增1并在递增后返回新值。它相当于i++操作。
    // ai.getAndIncrement()- 以原子方式递增当前值并返回旧值。
    // ai.decrementAndGet()- 原子地将当前值减1并在减量后返回新值。它等同于i--操作。
    // ai.getAndDecrement()- 以原子方式递减当前值并返回旧值。

    public static void main(String[] args) {
        //创建一个任务r，交给20条线程去运行
        Runnable r = new MyRunnable();
        for (int i = 0; i < 1; i++) {
            new Thread(r).start();
        }


    }
}

class MyRunnable implements Runnable{
    private int count = 0;
    @Override
    public void run() {
        //methodA();
        //methodB();
        //methodC();
        //methodD();
        methodE();
    }

    //看这里-01：本方法验证了 i++;不具有元子性
    //在run()里面调用这个方法，会看出控制台输出的数字有中相同的
    public void methodA(){
        try {
            Thread.sleep(300);
            System.out.println(count++);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //看这里-02：当然，我们可以通过加锁的方法解决。会看到控制台输出的数字没有相同
    synchronized public void methodB(){
        try {
            Thread.sleep(300);
            System.out.println(count++);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //看这里-03：除了加锁，还可以用Atomic包下的原子类。会看到控制台输出的数字没有相同
    private AtomicInteger at = new AtomicInteger(0);
    public void methodC(){
        try {
            Thread.sleep(300);
            System.out.println(at.addAndGet(1));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //看这里-04：添加volatile对于i++是无效的。会看到控制台输出的数字有相同
    private volatile int myCount = 0;
    public void methodD(){
        try {
            Thread.sleep(300);
            System.out.println(myCount++);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //-----------------------------------------------
    //看这里-05：关于AtomicInteger
    public void methodE(){
        //创建AtomicInteger对象
        AtomicInteger ai = new AtomicInteger();//初始值是 0
        AtomicInteger ai2 = new AtomicInteger(100);//初始值是 100

        //get/set方法
        int v = ai.get();//-------------get()方法，0
        System.out.println(v);
        ai.set(1000);//-----------------set()方法，1000
        System.out.println(ai.get());

        // ai.addAndGet(),以原子方式将给定值添加到当前值，并在添加后返回新值。
        v = ai.addAndGet(5);//-----1005
        System.out.println(v);

        // 以下不再演示
        // ai.addAndGet()------- 以原子方式将给定值添加到当前值，并在添加后返回新值。
        // ai.getAndAdd()------- 以原子方式将给定值添加到当前值并返回旧值。
        // ai.incrementAndGet()- 以原子方式将当前值递增1并在递增后返回新值。它相当于i++操作。
        // ai.getAndIncrement()- 以原子方式递增当前值并返回旧值。
        // ai.decrementAndGet()- 原子地将当前值减1并在减量后返回新值。它等同于i--操作。
        // ai.getAndDecrement()- 以原子方式递减当前值并返回旧值。

    }
}



